import { post } from '../../utils/request'
import { isFunction } from '../../utils'

/**
 * 内部数据缓存对象
 */
function InnerCaches() {
  this.datas = {}

  this.contains = function(modelName, id) {
    const datas = this.getDatas(modelName)
    return !!datas[id]
  }

  this.getData = function(modelName, id) {
    const datas = this.getDatas(modelName)
    return datas[id]
  }

  this.getDatas = function(modelName) {
    const datas = this.datas[modelName] || (this.datas[modelName] = {})
    return datas
  }

  this.setData = function(modelName, id, data) {
    const datas = this.getDatas(modelName)
    const cacheData = datas[id]
    if (cacheData) {
      Object.assign(cacheData, data)
      return cacheData
    }
    datas[id] = data
    return data
  }
}

/**
 * 所有实体的数据缓存
 */
const MODEL_DATA_CACEHS = new InnerCaches()

/**
 * 单例实体基类
 */
export default function ModelBase(name, config) {
  this.name = name
  this.config = {
    idField: 'id',
    methods: {},
    props: [],
    created: null,
    creating: null,
    saveUrl: null,
  }
  Object.assign(this.config, config)
}

/**
 * 是否存在指定id的数据
 * @param {*} id
 */
ModelBase.prototype.contains = function(id) {
  return MODEL_DATA_CACEHS.contains(this.name, id)
}

/**
 * 将一个数据推入缓存
 * @param {*} data
 */
ModelBase.prototype.push = function(data) {
  const id = data[this.config.idField]
  if (!id) {
    throw new Error('id field value required!')
  }
  data = MODEL_DATA_CACEHS.setData(this.name, id, data)
  return this.wrap(data)
}

/**
 * 包裹一个数据对象
 * @param {*} data
 */
ModelBase.prototype.wrap = function(data) {
  if (data._wrapped) {
    return data
  }
  Object.defineProperty(data, '_wrapped', {
    get() {
      return true
    },
  })
  const saveUrl = this.config.saveUrl
  if (saveUrl) {
    data.save = function() {
      const url = isFunction(saveUrl)
        ? saveUrl.apply(this, [...arguments])
        : saveUrl
      return post({
        url,
        data: this,
      })
    }
  }
  return data
}

/**
 * 创建数据对象并提交到服务器
 * @param {*} data
 */
ModelBase.prototype.create = function(data) {
  data = this.wrap(data)
  return data.save()
}

/**
 * 获取指定id的用户信息
 * @param {*} id
 */
ModelBase.prototype.get = function(id) {
  return MODEL_DATA_CACEHS.getData(this.name, id)
}

/**
 * 从缓存查询实体
 * @param {*} condition
 */
ModelBase.prototype.query = function(condition) {
  return Object.values(MODEL_DATA_CACEHS.getDatas(this.name)).filter(condition)
}
